#include "stdafx.h"
#include "GZip.h"




#define CHUNK 1024
int inflate_read(const char *source,int len,char **dest,int *destlen,bool gzip)
{
	int ret;
	unsigned have;
	z_stream strm;
	unsigned char out[CHUNK];
	int totalsize = 0;

	/* allocate inflate state */
	strm.zalloc = Z_NULL;
	strm.zfree = Z_NULL;
	strm.opaque = Z_NULL;
	strm.avail_in = 0;
	strm.next_in = Z_NULL;

	if(gzip)
		ret = inflateInit2(&strm, 47);
	else
		ret = inflateInit(&strm);

	if (ret != Z_OK)
		return ret;

	strm.avail_in = len;
	strm.next_in = (Byte*)source;

	/* run inflate() on input until output buffer not full */
	do 
	{
		strm.avail_out = CHUNK;
		strm.next_out = out;
		ret = inflate(&strm, Z_NO_FLUSH);
		assert(ret != Z_STREAM_ERROR); /* state not clobbered */
		switch (ret) 
		{
	
		case Z_NEED_DICT:
			ret = Z_DATA_ERROR; /* and fall through */
		case Z_DATA_ERROR:
		case Z_MEM_ERROR:
			inflateEnd(&strm);
			return ret;
		}

		have = CHUNK - strm.avail_out;
		totalsize += have;
		*dest = (char*)realloc(*dest,totalsize);
		memcpy(*dest + totalsize - have,out,have);

	} while (strm.avail_out == 0);

	/* clean up and return */
	(void)inflateEnd(&strm);

	*destlen = totalsize;
	return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}

int deflate_write(const char* raw,int len,char** compressbuf,int *destlen)
{
	//destLen > (sourceLen + 12)*100.1%


	ULONG uLen =(len+12)*1.001;
	byte* tempbuf = (byte*)malloc(uLen);
	int nRet = compress2(tempbuf,&uLen,(const byte*)raw,len,Z_DEFAULT_COMPRESSION);
	if (nRet == Z_OK)
	{	
		UINT c1 =adler32(0,0,0);;
		c1 = adler32(c1,(const byte*)raw,len);

		*destlen = uLen ;
		*compressbuf = (char*)malloc(uLen );
		memcpy(*compressbuf,tempbuf,uLen);
		

		free(tempbuf);
		return nRet;
	}

	return -1;
}

bool MakeGZFile(const char* szPath,const char* pBuf,int nLen)
{
	
	gzFile fData = gzopen(szPath,"wb");
	if (fData)
	{
		gzwrite(fData,pBuf,nLen);
		gzclose(fData); 

		return true;
	}
	
	return false;
		
}

bool MakeGZBuffer(const char* pSourceBuf,int nSourceLen,char** pDestBuf,int* nDestLen)
{

	ULONG uLen =(nSourceLen+12)*1.001;
	byte* tempbuf = (byte*)malloc(uLen);
	int nRet = compress2(tempbuf,&uLen,(const byte*)pSourceBuf,nSourceLen,Z_DEFAULT_COMPRESSION);
	if (nRet == Z_OK)
	{	
		UINT c1 =crc32(0,0,0);;
		c1 = crc32(c1,(const byte*)pSourceBuf,nSourceLen);
		UINT len = nSourceLen;
		char head[3]={0x1f,0x8b,0x08};
		int nDeflate = uLen-2-4;
		*nDestLen = nDeflate+10+8;

		*pDestBuf = (char*)malloc(*nDestLen);
		char * pCur = *pDestBuf;

		memset(pCur,0,*nDestLen);
		memcpy(pCur,head,3);
		pCur += 10;
		memcpy(pCur,tempbuf+2,nDeflate);
		pCur += nDeflate;
		memcpy(pCur,&c1,4);
		pCur += 4;
		memcpy(pCur,&len,4);
		pCur += 4;

		free(tempbuf);
		return true;
	}

	return false;

}

CGZipCreator::CGZipCreator()
{
	m_strm = new z_stream;
	m_File = NULL;
	m_nTotalRead = 0;
}

CGZipCreator::~CGZipCreator()
{
	if (m_strm)
	{
		delete m_strm;
		m_strm = NULL;
	}

	if (m_File)
	{
		delete m_File;
		m_File = NULL;
	}
}

bool CGZipCreator::Init(const CString& strFilePath)
{
	
	try
	{
		m_File = new CFile;
		m_File->Open(strFilePath,CFile::modeRead|CFile::shareDenyWrite);

		memset(m_strm,0,sizeof(z_stream));
		
		int ret = deflateInit2(m_strm,Z_DEFAULT_COMPRESSION,Z_DEFLATED, MAX_WBITS+16,8, Z_DEFAULT_STRATEGY);
		if (Z_OK != ret)
		{
			return false;
		}

		return true;
	}
	catch (CMemoryException* e)
	{
		
	}
	catch (CFileException* e)
	{
	}
	catch (CException* e)
	{
	}

	return false;
}

int CGZipCreator::GetGZipBuffer(byte* pBuf,int nLen)
{
	
	int nRet = -1;
	try
	{
		byte *pInBuf = new byte[nLen];
		int nInLen = nLen;

		int nRead = m_File->Read(pInBuf,nInLen);
		if (nRead > 0)
		{
			m_nTotalRead += nRead;

			m_strm->next_in = pInBuf;
			m_strm->avail_in = nRead;

			m_strm->next_out = pBuf;
			m_strm->avail_out = nLen;

			int flush = (m_nTotalRead < m_File->GetLength())?Z_FULL_FLUSH:Z_FINISH;

			int ret = deflate(m_strm,flush);
			if (Z_OK == ret ||Z_STREAM_END == ret)
			{
				nRet = nLen - m_strm->avail_out;
			}

		}
		else
		{
			deflateEnd(m_strm);
		}

		delete pInBuf;
	

	}
	catch (CMemoryException* e)
	{
		
	}
	catch (CFileException* e)
	{
	}
	catch (CException* e)
	{
	}

	return nRet;
}


